/*
 * Copyright 2007 - The JDPF Project Team (http://www.jdpf.org) 
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); 
 * you may not use this file except in compliance with the License. 
 * You may obtain a copy of the License at 
 * 
 * http://www.apache.org/licenses/LICENSE-2.0 
 * 
 * Unless required by applicable law or agreed to in writing, software 
 * distributed under the License is distributed on an "AS IS" BASIS, 
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and 
 * limitations under the License. 
 */
package org.jdpf.core.kernel.elements;

import java.util.ArrayList;
import java.util.List;

import org.jdpf.core.kernel.exceptions.CoreException;
import org.jdpf.core.kernel.exceptions.CoreExceptionsEnum;
import org.jdpf.core.kernel.execution.Task;

/**
 * Represents the abstract network.
 * 
 * @author Paolo Ciccarese
 */
public class Net {

	private static final String NO_START = "No start places detected in the network with name ";
	private static final String NO_END = "No end places detected in the network with name ";
	
	private List<Place> places = new ArrayList<Place>();
	private List<ITransition> transitions = new ArrayList<ITransition>();
	private List<InputArc> inputArcs = new ArrayList<InputArc>();
	private List<OutputArc> outputArcs = new ArrayList<OutputArc>();

	/**
	 * For recording the wiring validity
	 */
	private boolean valid;

	/**
	 * Network name
	 */
	private String name;

	public void add(InputArc inputArc) {
		inputArcs.add(inputArc);
	}

	public List<InputArc> getAllInputArcs() {
		return inputArcs;
	}

	public void add(OutputArc outputArc) {
		outputArcs.add(outputArc);
	}

	public List<OutputArc> getAllOutputArcs() {
		return outputArcs;
	}

	public void add(Place place) {
		places.add(place);
	}

	public List<Place> getAllPlaces() {
		return places;
	}

	public void add(ITransition transition) {
		transitions.add(transition);
	}
	
	public void addInspector(ITransition transition){
		transitions.add(0, transition);
	}

	public List<ITransition> getAllTransitions() {
		return transitions;
	}

	/**
	 * This method return the List of start places in the net. A start place is
	 * a place without Input Arcs.
	 * 
	 * @return The list of start places
	 * @throws CoreException
	 */
	public List<Place> getStartPlaces() throws CoreException {
		List<Place> startPlaces = new ArrayList<Place>();

		for (Place place : places) {
			if (place.isStartPlace()) {
				startPlaces.add(place);
			}
		}
		if (startPlaces.size() == 0)
			throw new CoreException(CoreExceptionsEnum.NoStartPlace,
					Net.NO_START + this.name);
		else
			return startPlaces;
	}

	/**
	 * This method return the List of end places in the net. An end place is a
	 * place without Output Arcs. A RuntimeException is throwed if no end places
	 * has been detected.
	 * 
	 * @return The List of end places in the net
	 */
	public List<Place> getEndPlaces() throws CoreException {
		List<Place> endPlaces = new ArrayList<Place>();

		for (Place place : places) {
			if (place.isEndPlace()) {
				endPlaces.add(place);
			}
		}
		if (endPlaces.size() == 0)
			throw new CoreException(CoreExceptionsEnum.NoEndPlace, Net.NO_END
					+ this.name);
		else
			return endPlaces;
	}

	public String toString() {
		StringBuilder sb = new StringBuilder();
		sb.append("[" + this.getName() + "]");
		sb.append("\t[Places]\n");
		for (Place p : places) {
			sb.append("\t" + p.toString() + "\n");
		}
		sb.append("[Transitions]\n");
		for (ITransition t : transitions) {
			sb.append("\t" + t.toString() + "\n");
		}
		sb.append("[InputArcs]\n");
		for (InputArc a : inputArcs) {
			sb.append("\t" + a.toString() + "\n");
		}
		sb.append("[OutputArcs]\n");
		for (OutputArc o : outputArcs) {
			sb.append("\t" + o.toString() + "\n");
		}
		return sb.toString();
	}

	public boolean isValid() {
		return valid;
	}

	public void setValid(boolean valid) {
		this.valid = valid;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}
}
